package pe.tnova.generic.structure.project.springmvc.soruce;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.widgets.Shell;

import pe.tnova.generic.structure.project.springmvc.UI.ArchivoGenericoBean;
import pe.tnova.generic.structure.project.springmvc.UI.OptionEntidadBean;
import pe.tnova.generic.structure.project.springmvc.UI.PanelConfiguracionUI;
import pe.tnova.generic.structure.project.springmvc.util.ConstantesTNOVA;
import pe.tnova.generic.structure.project.springmvc.util.PluginException;
import pe.tnova.generic.structure.project.springmvc.util.PluginUtil;

public class ProjectScanCore {

	private static final Logger LOG = Logger.getLogger(ProjectScanCore.class.getName());

	private List<OptionEntidadBean> configuracionEntidades;
	private List<String> nombreEntidadesDAOImpl;
	private List<String> nombreEntidadesDAOBaseImpl;
	private List<String> nombreEntidadesService;
	private List<String> nombreEntidadesServiceMantenimiento;
	private List<ICompilationUnit> listaICompilationUnits = null;
	private IProject project = null;
	private IJavaProject javaProject = null;
	private IFolder srcJAVA = null;
	private IFolder srcRESOURCE = null;
	private String strPackageBase;
	private SourceProjectCore sourceProjectCore;
	private ArchivoGenericoBean archivoGenericoBean;
	private boolean faltanArchivosIniciales;

	private ProjectScanCore(IProject project) {
		this.project = project;
		this.javaProject = JavaCore.create(project);
		this.srcJAVA = project.getFolder(ConstantesTNOVA.SOURCE_JAVA);
		this.srcRESOURCE = project.getFolder(ConstantesTNOVA.RESOURCES);
		archivoGenericoBean = new ArchivoGenericoBean();
	}

	public static ProjectScanCore getInstance(IProject project) {
		return new ProjectScanCore(project);
	}

	public void scanPOM() throws Exception {
		IResource pom = project.findMember("pom.xml");
		try {
			if (pom.exists()) {
				IFile archivoPOM = ((IFile) pom);
				InputStream contents = archivoPOM.getContents();
				String strPOM = PluginUtil.getStringBuilderFromInputStream(contents);
				if (strPOM.indexOf(ConstantesTNOVA.POM_DEPENDENCY_TNOVA_CORE) > 0) {
					return;
				} else {
					int posionDependency = strPOM.lastIndexOf(ConstantesTNOVA.POM_END_DEPENDENCY);
					int posionDependencies = strPOM.lastIndexOf(ConstantesTNOVA.POM_END_DEPENDENCIES);
					String pomXMLNuevo = strPOM.substring(0, posionDependency) + ConstantesTNOVA.POM_DEPENDENCY_TNOVA_CORE + strPOM.substring(posionDependencies, strPOM.length());
					archivoPOM.setContents(new ByteArrayInputStream(pomXMLNuevo.getBytes()), IFile.FORCE | IFile.KEEP_HISTORY, new NullProgressMonitor());
					LOG.info("TNOVA Core dependency ha sido generado en la version 1.0.0");
				}
			} else {
				throw new PluginException("No Existe pom.xml");
			}
		} catch (Exception e) {
			throw new Exception("Ocurrio un error " + e.getMessage());
		}
	}

	public void scanPersisnteceXML() throws Exception {
		IFile persisntece = srcRESOURCE.getFile(ConstantesTNOVA.META_INF + ConstantesTNOVA.SLASH + ConstantesTNOVA.PERSISTENCE);
		try {
			if (persisntece.exists()) {
				return;
			} else {
				archivoGenericoBean.setExistsPersistence(false);
				throw new PluginException("No Existe persistence.xml");
			}
		} catch (Exception e) {
			throw new Exception("Ocurrio un error " + e.getMessage());
		}
	}

	private String buscarPackageParentCore() throws Exception {
		IFile appContextSpring = srcRESOURCE.getFile(ConstantesTNOVA.META_INF + ConstantesTNOVA.SLASH + ConstantesTNOVA.CARP_SPRING + ConstantesTNOVA.SLASH
				+ ConstantesTNOVA.APP_CONTEXT_XML);
		try {
			if (appContextSpring.exists()) {
				IFile archivoSpringXML = ((IFile) appContextSpring);
				InputStream contents = archivoSpringXML.getContents();
				String strSpringXML = PluginUtil.getStringBuilderFromInputStream(contents);
				int posionConext = strSpringXML.lastIndexOf(ConstantesTNOVA.APP_CONTEXT_XML_CONTEXT_COMPONENT_SCAN_INIT)
						+ ConstantesTNOVA.APP_CONTEXT_XML_CONTEXT_COMPONENT_SCAN_INIT.length();
				int posionEndConext = strSpringXML.lastIndexOf(ConstantesTNOVA.APP_CONTEXT_XML_CONTEXT_COMPONENT_SCAN_END);
				String packContext = strSpringXML.substring(posionConext, posionEndConext);
				return packContext;
			} else {
				archivoGenericoBean.setExistsPersistence(false);
				archivoGenericoBean.setExistsSpringPorperties(false);
				throw new PluginException("No Existe " + ConstantesTNOVA.APP_CONTEXT_XML);
			}
		} catch (Exception e) {
			throw new Exception("Ocurrio un error " + e.getMessage());
		}
	}

	public void scanDominioConfiguracion(Shell shell) throws Exception {
		strPackageBase = buscarPackageParentCore();
		LOG.info(strPackageBase);
		if (!PluginUtil.isNull(strPackageBase)) {
			sourceProjectCore = SourceProjectCore.getInstance(project, javaProject, srcJAVA);
			sourceProjectCore.packageBase(strPackageBase);
			if (sourceProjectCore.existe(ConstantesTNOVA.PACK_DOMINIO)) {
				LOG.info("Existe dominio");
				scanDominio(ConstantesTNOVA.PACK_DOMINIO);
				scanDAO();
				scanDAOBase();
				scanService();
				scanServiceMant();
				
				PanelConfiguracionUI configuracionUI = new PanelConfiguracionUI(shell, configuracionEntidades);
				configuracionUI.create();
				if (configuracionUI.isExistsEntidades() && configuracionUI.open() == Window.OK) {
					configuracionEntidades = configuracionUI.getConfiguracionEntidades();
					sourceProjectCore.generarCapaDAO(configuracionEntidades);
					sourceProjectCore.generarDAOBaseConfig(configuracionEntidades);
					sourceProjectCore.generarCapaDAOBASE(configuracionEntidades);
					sourceProjectCore.generarCapaService(configuracionEntidades);
					sourceProjectCore.generarCapaServiceMantenimiento(configuracionEntidades);
				}
			} else {
				throw new Exception("No existe paquete dominio");
			}
		}
	}

	private void scanService() throws JavaModelException {
		if (!sourceProjectCore.existe(ConstantesTNOVA.PACK_SERVICE)) {
			sourceProjectCore.createPackate(strPackageBase + ConstantesTNOVA.DONT + ConstantesTNOVA.PACK_SERVICE, true);
		}
		if (!sourceProjectCore.existe(ConstantesTNOVA.PACK_SERVICE_IMPL)) {
			sourceProjectCore.createPackate(strPackageBase + ConstantesTNOVA.DONT + ConstantesTNOVA.PACK_SERVICE_IMPL, true);
			generarCodigoService(true,null);
		}
	}	

	private void scanServiceMant() throws JavaModelException {
		if (!sourceProjectCore.existe(ConstantesTNOVA.PACK_SERVICE_MNT)) {
			sourceProjectCore.createPackate(strPackageBase + ConstantesTNOVA.DONT + ConstantesTNOVA.PACK_SERVICE_MNT, true);
		}
		if (!sourceProjectCore.existe(ConstantesTNOVA.PACK_SERVICE_MNT_IMPL)) {
			sourceProjectCore.createPackate(strPackageBase + ConstantesTNOVA.DONT + ConstantesTNOVA.PACK_SERVICE_MNT_IMPL, true);
			generarCodigoServiceManteni(true,null);
		}else{
			generarCodigoServiceManteni(false, null);
			nombreEntidadesServiceMantenimiento = new ArrayList<String>();
			IPackageFragment pack = sourceProjectCore.getPackage(strPackageBase + ConstantesTNOVA.DONT + ConstantesTNOVA.PACK_SERVICE_MNT_IMPL, false);
			ICompilationUnit[] compilationUnit = pack.getCompilationUnits();
			String strEntidad = null;
			for (ICompilationUnit icom : compilationUnit) {
				strEntidad = PluginUtil.getNameFile(icom.getElementName());
				strEntidad = strEntidad.substring(0,strEntidad.indexOf(ConstantesTNOVA.CLASS_SERVICE_MNT_IMPL));
				nombreEntidadesServiceMantenimiento.add(strEntidad);
			}
			generarCodigoServiceManteni(true, nombreEntidadesDAOBaseImpl);
		}
	}

	private void scanDAO() throws JavaModelException {
		if (!sourceProjectCore.existe(ConstantesTNOVA.PACK_DAO)) {
			sourceProjectCore.createPackate(strPackageBase + ConstantesTNOVA.DONT + ConstantesTNOVA.PACK_DAO, true);
		}
		if (!sourceProjectCore.existe(ConstantesTNOVA.PACK_DAO_IMPL)) {
			sourceProjectCore.createPackate(strPackageBase + ConstantesTNOVA.DONT + ConstantesTNOVA.PACK_DAO_IMPL, true);
			generarCodigoDAO(true,null);
		} else {
			// analizar que clases ya estan creadas
			generarCodigoDAO(false,null);
			nombreEntidadesDAOImpl = new ArrayList<String>();
			IPackageFragment pack = sourceProjectCore.getPackage(strPackageBase + ConstantesTNOVA.DONT + ConstantesTNOVA.PACK_DAO_IMPL, false);
			ICompilationUnit[] compilationUnit = pack.getCompilationUnits();
			String strEntidad = null;
			for (ICompilationUnit icom : compilationUnit) {
				strEntidad = PluginUtil.getNameFile(icom.getElementName());
				strEntidad = strEntidad.substring(0,strEntidad.indexOf(ConstantesTNOVA.CLASS_DAO_IMPL));
				nombreEntidadesDAOImpl.add(strEntidad);
			}
			generarCodigoDAO(true, nombreEntidadesDAOImpl);
		}
	}

	private void scanDAOBase() throws JavaModelException {
		if (!sourceProjectCore.existe(ConstantesTNOVA.PACK_DAO_BASE)) {
			sourceProjectCore.createPackate(strPackageBase + ConstantesTNOVA.DONT + ConstantesTNOVA.PACK_DAO_BASE, true);
		}
		if (!sourceProjectCore.existe(ConstantesTNOVA.PACK_DAO_BASE_IMPL)) {
			sourceProjectCore.createPackate(strPackageBase + ConstantesTNOVA.DONT + ConstantesTNOVA.PACK_DAO_BASE_IMPL, true);
			generarCodigoDAOBase(true, null);
		} else {
			// analizar que clases ya estan creadas
			generarCodigoDAOBase(false, null);
			nombreEntidadesDAOBaseImpl = new ArrayList<String>();
			IPackageFragment pack = sourceProjectCore.getPackage(strPackageBase + ConstantesTNOVA.DONT + ConstantesTNOVA.PACK_DAO_BASE_IMPL, false);
			ICompilationUnit[] compilationUnit = pack.getCompilationUnits();
			String strEntidad = null;
			for (ICompilationUnit icom : compilationUnit) {
				strEntidad = PluginUtil.getNameFile(icom.getElementName());
				strEntidad = strEntidad.substring(0,strEntidad.indexOf(ConstantesTNOVA.CLASS_DAO_BASE_IMPL));
				nombreEntidadesDAOBaseImpl.add(strEntidad);
			}
			generarCodigoDAOBase(true, nombreEntidadesDAOBaseImpl);
		}
	}

	private void generarCodigoDAO(boolean b, List<String> nombreExistentes) {
		boolean existe = (nombreExistentes != null && !(nombreExistentes.isEmpty()));
		for (OptionEntidadBean optionEntidadBean : configuracionEntidades) {
			optionEntidadBean.setCheckGeneraCodigoDAO(b);
			if (existe) {
				for (String nombre : nombreExistentes) {
					if(nombre.equals(optionEntidadBean.getNombreEntidad())){
						optionEntidadBean.setCheckGeneraCodigoDAO(false);
					}
				}
			}
		}
	}

	private void generarCodigoDAOBase(boolean b, List<String> nombreExistentes) {
		boolean existe = (nombreExistentes != null && !(nombreExistentes.isEmpty()));
		for (OptionEntidadBean optionEntidadBean : configuracionEntidades) {
			optionEntidadBean.setCheckGeneraCodigoDAOBASE(b);
			if (existe) {
				for (String nombre : nombreExistentes) {
					if(nombre.equals(optionEntidadBean.getNombreEntidad())){
						optionEntidadBean.setCheckGeneraCodigoDAOBASE(false);
					}
				}
			}
		}		
	}

	private void generarCodigoService(boolean b, List<String> nombreExistentes) {
		boolean existe = (nombreExistentes != null && !(nombreExistentes.isEmpty()));
		for (OptionEntidadBean optionEntidadBean : configuracionEntidades) {
			optionEntidadBean.setCheckGeneraCodigoSERVICEMant(b);
			if (existe) {
				for (String nombre : nombreExistentes) {
					if(nombre.equals(optionEntidadBean.getNombreEntidad())){
						optionEntidadBean.setCheckGeneraCodigoSERVICE(false);
					}
				}
			}
		}		
	}
	
	private void generarCodigoServiceManteni(boolean b, List<String> nombreExistentes) {
		boolean existe = (nombreExistentes != null && !(nombreExistentes.isEmpty()));
		for (OptionEntidadBean optionEntidadBean : configuracionEntidades) {
			optionEntidadBean.setCheckGeneraCodigoSERVICEMant(b);
			if (existe) {
				for (String nombre : nombreExistentes) {
					if(nombre.equals(optionEntidadBean.getNombreEntidad())){
						optionEntidadBean.setCheckGeneraCodigoSERVICEMant(false);
					}
				}
			}
		}		
	}
	

	private void scanDominio(String strPack) throws Exception {
		LOG.info("Instanciando las clases dentro del paquete " + strPack);
		sourceProjectCore.standarDominio();
		LOG.info("Escaneo terminado en le paquete " + strPack);
		setListaICompilationUnits(sourceProjectCore.getListaICompilationUnits());
		configuracionEntidades = new ArrayList<OptionEntidadBean>();
		OptionEntidadBean optionEntidadBean;
		AnalisyEntityClass analisyEntityClass = null;
		for (ICompilationUnit compilationUnit : listaICompilationUnits) {
			optionEntidadBean = new OptionEntidadBean();
			optionEntidadBean.setNombreEntidad(PluginUtil.getNameFile(compilationUnit.getElementName()));
			optionEntidadBean.setCompilationUnit(compilationUnit);
			analisyEntityClass = AnalisyEntityClass.newInstace(optionEntidadBean,strPackageBase+ ConstantesTNOVA.DONT+ strPack);
			analisyEntityClass.setEstablecerAtributosEntidad();
			analisyEntityClass.setEstablecerValorCBO();
			analisyEntityClass.setConstructores();
			configuracionEntidades.add(optionEntidadBean);
		}
	}

	public void generarArchivoInit() throws CoreException {
		LOG.info("Generando los archivos iniciales core " + archivoGenericoBean.getDescrpcionContextXMLCoreTest());
		String strContentFile = null;
		IFile ifile = null;
		InputStream io = null;
		{
			ifile = srcRESOURCE.getFile(ConstantesTNOVA.META_INF + ConstantesTNOVA.SLASH + ConstantesTNOVA.PERSISTENCE);
			io = getClass().getResourceAsStream(ConstantesTNOVA.FILE_PERSISTENCE);
			strContentFile = PluginUtil.getStringBuilderFromInputStream(io);
			strContentFile = strContentFile.replaceAll(ConstantesTNOVA.TOKEN_NAME_PERSISNTECE, archivoGenericoBean.getNamePersisteceContextXMLCoreTest());
			ifile.create(PluginUtil.getIO(strContentFile), true, null);

		}
		{
			ifile = srcRESOURCE.getFile(ConstantesTNOVA.META_INF + ConstantesTNOVA.SLASH + ConstantesTNOVA.SPRINT_CONECTION);
			io = getClass().getResourceAsStream(ConstantesTNOVA.FILE_SPRING_PROPERTIES);
			strContentFile = PluginUtil.getStringBuilderFromInputStream(io);
			strContentFile = strContentFile.replaceAll(ConstantesTNOVA.TOKEN_CADENA_CONEXION, archivoGenericoBean.getJdbcConexionPropertiesCore())
					.replaceAll(ConstantesTNOVA.TOKEN_DRIVE, archivoGenericoBean.getJdbcDrivePropertiesCore())
					.replaceAll(ConstantesTNOVA.TOKEN_USUARIO, archivoGenericoBean.getJdbcUserPropertiesCore())
					.replaceAll(ConstantesTNOVA.TOKEN_PASSWORD, archivoGenericoBean.getJdbcPassPropertiesCore());
			ifile.create(PluginUtil.getIO(strContentFile), true, null);
		}
		{
			ifile = srcRESOURCE.getFile(ConstantesTNOVA.META_INF + ConstantesTNOVA.SLASH + ConstantesTNOVA.CARP_SPRING + ConstantesTNOVA.SLASH + ConstantesTNOVA.APP_CONTEXT_XML);
			io = getClass().getResourceAsStream(ConstantesTNOVA.FILE_APP_CONTEXT_SPRING);
			strContentFile = PluginUtil.getStringBuilderFromInputStream(io);
			strContentFile = strContentFile.replaceAll(ConstantesTNOVA.TOKEN_DESCRIPCION, archivoGenericoBean.getDescrpcionContextXMLCoreTest())
					.replaceAll(ConstantesTNOVA.TOKEN_PACK_CORE, archivoGenericoBean.getPackCoreContextXMLCoreTest())
					.replaceAll(ConstantesTNOVA.TOKEN_NAME_PERSISNTECE, archivoGenericoBean.getNamePersisteceContextXMLCoreTest());
			ifile.create(PluginUtil.getIO(strContentFile), true, null);
		}
	}

	public List<ICompilationUnit> getListaICompilationUnits() {
		return listaICompilationUnits;
	}

	public void setListaICompilationUnits(List<ICompilationUnit> listaICompilationUnits) {
		this.listaICompilationUnits = listaICompilationUnits;
	}

	public List<OptionEntidadBean> getConfiguracionEntidades() {
		return configuracionEntidades;
	}

	public void setConfiguracionEntidades(List<OptionEntidadBean> configuracionEntidades) {
		this.configuracionEntidades = configuracionEntidades;
	}

	public ArchivoGenericoBean getArchivoGenericoBean() {
		return archivoGenericoBean;
	}

	public void setArchivoGenericoBean(ArchivoGenericoBean archivoGenericoBean) {
		this.archivoGenericoBean = archivoGenericoBean;
	}

	public boolean isFaltanArchivosIniciales() {
		faltanArchivosIniciales = archivoGenericoBean.isExistsContextXML() && archivoGenericoBean.isExistsPersistence() && archivoGenericoBean.isExistsSpringPorperties();
		return faltanArchivosIniciales;
	}

	public void setFaltanArchivosIniciales(boolean faltanArchivosIniciales) {
		this.faltanArchivosIniciales = faltanArchivosIniciales;
	}

	public List<String> getNombreEntidadesServiceMantenimiento() {
		return nombreEntidadesServiceMantenimiento;
	}

	public void setNombreEntidadesServiceMantenimiento(List<String> nombreEntidadesServiceMantenimiento) {
		this.nombreEntidadesServiceMantenimiento = nombreEntidadesServiceMantenimiento;
	}

}
